#include <QtGui>

#include "mainwindowimpl.h"
#include "searchboximpl.h"
#include "styleeditorimpl.h"
#include "configurationdlgimpl.h"
#include "aboutdialogimpl.h"

/*
	MainWindow construtor.
*/
MainWindowImpl::MainWindowImpl( QWidget * parent, Qt::WFlags f)
        : QMainWindow(parent, f)
{
	// Setup UI
    setupUi(this);
    createTreeDock();
    createSearchDock();
    createFontWidgets();
    createContextMenu();
    createSysTray();
    FinalizeUI();

    mainModel = NULL;
    m_closeFromMenu = false;

	// Load and apply configuration
    m_confManager = new ConfigurationManager(this->AppName());
    applyConfiguration();

	// Load styles
    m_styleManager = new StyleManager();
    m_styleManager->updateComboStyle(comboStyle);

	// Read window, toolbars and docks size/position.
    readSettings();

	// Open last file if requested.
    if (m_confManager->openLastFile)
        openFile(m_confManager->lastFile);
}

/*
	Some kind of "constants". Maybe to be done another way.
*/
QString MainWindowImpl::AppDisplayName()
{
    return "Nagaina";
}

QString MainWindowImpl::AppName()
{
    return "nagaina";
}

QString MainWindowImpl::AppVersion()
{
    return "0.1.1";
}

QString MainWindowImpl::AppEditor()
{
    return "JD";
}

/*
	UI complementary implementation.
*/

/*
	Misc. UI stuff.
*/
void MainWindowImpl::FinalizeUI()
{
	// Main window title
    this->setWindowTitle(AppDisplayName() + " - " + AppVersion());

	// Add toolbar to menu
    menu_Toolbars->addAction(fileToolBar->toggleViewAction());
    menu_Toolbars->addAction(editToolBar->toggleViewAction());
    menu_Toolbars->addAction(formatToolBar->toggleViewAction());
    menu_Toolbars->addAction(styleToolBar->toggleViewAction());
    menu_Toolbars->addAction(fontToolBar->toggleViewAction());

	// Initialize "paste" action.
    connect(QApplication::clipboard(), SIGNAL(dataChanged()), this, SLOT(onClipboardDataChanged()));        
    actionPaste->setEnabled(!QApplication::clipboard()->text().isEmpty());   
	
    onFontChanged(textEdit->font());
    onColorChanged(textEdit->textColor());
    onAlignmentChanged(textEdit->alignment());
}

/*
	Create police and size combo boxes, and alignement actions.
*/
void MainWindowImpl::createFontWidgets()
{
    // Style tool bar
    styleToolBar = new QToolBar(this);
    styleToolBar->setObjectName("styleToolBar");
    styleToolBar->setAllowedAreas(Qt::TopToolBarArea | Qt::BottomToolBarArea | Qt::LeftToolBarArea | Qt::RightToolBarArea);
    styleToolBar->setWindowTitle(tr("Styles"));
    addToolBarBreak(Qt::TopToolBarArea);
    addToolBar(styleToolBar);

    comboStyle = new QComboBox(styleToolBar);
    comboStyle->setObjectName("comboStyle");
    comboStyle->setEditable(false);
    comboStyle->setSizeAdjustPolicy(QComboBox::AdjustToContents);
    styleToolBar->addWidget(comboStyle);
    connect(action_Apply_current_style, SIGNAL(triggered()), this, SLOT(on_action_Apply_current_style_triggered()));
    styleToolBar->addAction(action_Apply_current_style);

    // Create Toolbar for size and police combos.
    fontToolBar = new QToolBar(this);
    fontToolBar->setObjectName("fontToolBar");
    fontToolBar->setAllowedAreas(Qt::TopToolBarArea | Qt::BottomToolBarArea | Qt::LeftToolBarArea | Qt::RightToolBarArea);
    fontToolBar->setWindowTitle(tr("Font"));
    addToolBar(fontToolBar);

    // Police combo.
    comboFont = new QFontComboBox(fontToolBar);
    fontToolBar->addWidget(comboFont);
    connect(comboFont, SIGNAL(activated(const QString &)),
            this, SLOT(onTextFamily(const QString &)));
    comboFont->setEditable(false);

    // Size combo.
    comboSize = new QComboBox(fontToolBar);
    comboSize->setObjectName("comboSize");
    fontToolBar->addWidget(comboSize);
    comboSize->setEditable(false);

    // Fill size combo.
    QFontDatabase db;
    foreach(int size, db.standardSizes())
    comboSize->addItem(QString::number(size));
    connect(comboSize, SIGNAL(activated(const QString &)), this, SLOT(onTextSize(const QString &)));
    comboSize->setCurrentIndex(comboSize->findText(QString::number(QApplication::font().pointSize())));

    // Color action : draw with current color.
    QPixmap pix(16, 16);
    pix.fill(Qt::black);
    action_Color->setIcon(pix);

    // Alignment actions.
    QActionGroup *grp = new QActionGroup(this);
    connect(grp, SIGNAL(triggered(QAction *)), this, SLOT(onTextAlign(QAction *)));

    actionAlignLeft = new QAction(QIcon(":/textleft.png"), tr("&Left"), grp);
    actionAlignLeft->setShortcut(Qt::CTRL + Qt::Key_L);
    actionAlignLeft->setCheckable(true);
    actionAlignCenter = new QAction(QIcon(":/textcenter.png"), tr("C&enter"), grp);
    actionAlignCenter->setShortcut(Qt::CTRL + Qt::Key_E);
    actionAlignCenter->setCheckable(true);
    actionAlignRight = new QAction(QIcon(":/textright.png"), tr("&Right"), grp);
    actionAlignRight->setShortcut(Qt::CTRL + Qt::Key_R);
    actionAlignRight->setCheckable(true);
    actionAlignJustify = new QAction(QIcon(":/textjustify.png"), tr("&Justify"), grp);
    actionAlignJustify->setShortcut(Qt::CTRL + Qt::Key_J);
    actionAlignJustify->setCheckable(true);

    formatToolBar->addActions(grp->actions());
    menuAlignment->addActions(grp->actions());
}

/*
	Create Systray object
*/
void MainWindowImpl::createSysTray()
{
    actionSysShow = new QAction(tr("Show"), this);
    connect(actionSysShow, SIGNAL(triggered( )), this, SLOT(onActionSysShow( )));
    actionSysClose = new QAction(QIcon(":/exit.png"), tr("Quit"), this);
    connect(actionSysClose, SIGNAL(triggered( )), this, SLOT(onActionSysClose( )));
    sysTrayMenu = new QMenu(this);
    sysTrayMenu->addAction(actionSysShow);
    sysTrayMenu->addSeparator();
    sysTrayMenu->addAction(actionSysClose);

    m_trayIcon = new QSystemTrayIcon(QIcon(":/nagaina.png"), this);
    m_trayIcon->setToolTip(AppDisplayName());
    m_trayIcon->setContextMenu(sysTrayMenu);
    connect(m_trayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason )), this, SLOT(onTrayIconActivated(QSystemTrayIcon::ActivationReason )));
}

/*
	Create Tree Widget context menu.
*/
void MainWindowImpl::createContextMenu()
{
    actionAddRootCategory = new QAction(QIcon(":/addrootcategory.png"), tr("Add root category..."), this);
    connect(actionAddRootCategory, SIGNAL(triggered( )), this, SLOT(onActionAddRootCategory( )));
    actionAddRootPage = new QAction(QIcon(":/addrootpage.png"), tr("Add root page..."), this);
    connect(actionAddRootPage, SIGNAL(triggered( )), this, SLOT(onActionAddRootPage( )));

    actionMenuAddCategory = new QAction(QIcon(":/addcategory.png"), tr("Add category..."), this);
    connect(actionMenuAddCategory, SIGNAL(triggered( )), this, SLOT(onActionMenuAddCategory( )));
    actionMenuAddPage = new QAction(QIcon(":/addpage.png"), tr("Add page..."), this);
    connect(actionMenuAddPage, SIGNAL(triggered( )), this, SLOT(onActionMenuAddPage( )));
    actionMenuRename = new QAction(tr("Rename..."), this);
    connect(actionMenuRename, SIGNAL(triggered( )), this, SLOT(onActionMenuRename( )));
    actionMenuDelete = new QAction(QIcon(":/delete.png"), tr("Delete..."), this);
    connect(actionMenuDelete, SIGNAL(triggered( )), this, SLOT(onActionMenuDelete( )));

    actionMenuMoveLeft = new QAction(QIcon(":/leftarrow.png"), tr("Move left"), this);
    actionMenuMoveLeft->setShortcut(Qt::ALT + Qt::Key_Left);
    connect(actionMenuMoveLeft, SIGNAL(triggered( )), this, SLOT(onActionMenuMoveLeft( )));
    actionMenuMoveRight = new QAction(QIcon(":/rightarrow.png"), tr("Move right"), this);
    actionMenuMoveRight->setShortcut(Qt::ALT + Qt::Key_Right);
    connect(actionMenuMoveRight, SIGNAL(triggered( )), this, SLOT(onActionMenuMoveRight( )));
    actionMenuMoveUp = new QAction(QIcon(":/uparrow.png"), tr("Move up"), this);
    actionMenuMoveUp->setShortcut(Qt::ALT + Qt::Key_Up);
    connect(actionMenuMoveUp, SIGNAL(triggered( )), this, SLOT(onActionMenuMoveUp( )));
    actionMenuMoveDown = new QAction(QIcon(":/downarrow.png"), tr("Move down"), this);
    actionMenuMoveDown->setShortcut(Qt::ALT + Qt::Key_Down);
    connect(actionMenuMoveDown, SIGNAL(triggered( )), this, SLOT(onActionMenuMoveDown( )));

    actionAddRootCategory->setEnabled(false);
    actionAddRootPage->setEnabled(false);

    actionMenuAddCategory->setEnabled(false);
    actionMenuAddPage->setEnabled(false);
    actionMenuRename->setEnabled(false);
    actionMenuDelete->setEnabled(false);
    actionMenuMoveUp->setEnabled(false);
    actionMenuMoveDown->setEnabled(false);
    actionMenuMoveLeft->setEnabled(false);
    actionMenuMoveRight->setEnabled(false);

    // Add actions to context menu.
    contextMenu = new QMenu(this);
    contextMenu->addAction(actionMenuAddCategory);
    contextMenu->addAction(actionMenuAddPage);
    contextMenu->addSeparator();
    contextMenu->addAction(actionMenuMoveUp);
    contextMenu->addAction(actionMenuMoveDown);
    contextMenu->addAction(actionMenuMoveLeft);
    contextMenu->addAction(actionMenuMoveRight);
    contextMenu->addSeparator();
    contextMenu->addAction(actionMenuRename);
    contextMenu->addSeparator();
    contextMenu->addAction(actionMenuDelete);

    // Add actions to tree view tool bar
    treeToolBar->addAction(actionAddRootCategory);
    treeToolBar->addAction(actionAddRootPage);
    treeToolBar->addAction(actionMenuMoveUp);
    treeToolBar->addAction(actionMenuMoveDown);
    treeToolBar->addAction(actionMenuMoveLeft);
    treeToolBar->addAction(actionMenuMoveRight);

    // Add actions to main menu.
    menuItems->addAction(actionAddRootCategory);
    menuItems->addAction(actionAddRootPage);
    menuItems->addSeparator();
    menuItems->addAction(actionMenuAddCategory);
    menuItems->addAction(actionMenuAddPage);
    menuItems->addSeparator();
    menuItems->addAction(actionMenuMoveUp);
    menuItems->addAction(actionMenuMoveDown);
    menuItems->addAction(actionMenuMoveLeft);
    menuItems->addAction(actionMenuMoveRight);
    menuItems->addSeparator();
    menuItems->addAction(actionMenuRename);
    menuItems->addSeparator();
    menuItems->addAction(actionMenuDelete);
}

/*
	Create file TreeView in a dock.
*/
void MainWindowImpl::createTreeDock()
{
    QDockWidget *dock = new QDockWidget(tr("Explorer"), this);
    dock->setObjectName("dockExplorer");
    dock->setAllowedAreas(Qt::AllDockWidgetAreas);

    QWidget *container = new QWidget;
    container->setContentsMargins(0, 0, 0, 0);
    QVBoxLayout *layout = new QVBoxLayout();
    layout->setMargin(0);
    layout->setSpacing(0);

    treeWidget = new QTreeWidget(dock);
    treeWidget->setContextMenuPolicy(Qt::CustomContextMenu);
    treeWidget->setHeaderLabel("");

    connect(treeWidget, SIGNAL(itemClicked(QTreeWidgetItem *, int)), this, SLOT(onTreeClick(QTreeWidgetItem *, int)));
    connect(treeWidget, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(onTreeContextMenuRequested(QPoint)));
    connect(treeWidget, SIGNAL(currentItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)), this, SLOT(onCurrentItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)));

    treeToolBar = new QToolBar(dock);
    treeToolBar->setIconSize(QSize(20, 20));
    treeToolBar->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum));

    layout->addWidget(treeToolBar);
    layout->addWidget(treeWidget);

    container->setLayout(layout);

    dock->setWidget(container);
    addDockWidget(Qt::LeftDockWidgetArea, dock);
    menu_Display->addAction(dock->toggleViewAction());
}

/*
	Create advanced search dialog dock.
	Unused at the moment.
*/
void MainWindowImpl::createSearchDock()
{
    //searchDock = new QDockWidget(tr("Search"), this);
    //searchDock->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea | Qt::TopDockWidgetArea | Qt::BottomDockWidgetArea);
    searchBox = new SearchBoxImpl(0);
    searchDock = searchBox->dockWidget;

    addDockWidget(Qt::BottomDockWidgetArea, searchDock);
    searchDock->setFloating(true);
    // To be implemented
    //menu_Display->addAction(searchDock->toggleViewAction());
}

void MainWindowImpl::setEditorColor(QColor color)
{
    QVariant red = color.red();
    QVariant green = color.green();
    QVariant blue = color.blue();

    textEdit->setStyleSheet("QTextEdit { background-color: rgb(" + red.toString() + ", " + green.toString() + ", " + blue.toString() + "); }");
}

void MainWindowImpl::setTreeColor(QColor color)
{
    QVariant red = color.red();
    QVariant green = color.green();
    QVariant blue = color.blue();
    treeWidget->setStyleSheet("QTreeWidget { background-color: rgb(" + red.toString() + ", " + green.toString() + ", " + blue.toString() + "); }");
}

void MainWindowImpl::applyConfiguration()
{
    setEditorColor(m_confManager->editorColor);
    setTreeColor(m_confManager->treeColor);

    if (m_confManager->useTrayIcon)
        m_trayIcon->show();
    else
        m_trayIcon->hide();
}

/*
	Format modifications : implements changes in format.
*/

/*
	Apply format changes on text.
*/
void MainWindowImpl::mergeFormatOnWordOrSelection(const QTextCharFormat &format)
{
    QTextCursor cursor = textEdit->textCursor();
    /* Code from the example. Don't find it useful.
    if (!cursor.hasSelection())
        cursor.select(QTextCursor::WordUnderCursor);    
    */
    cursor.mergeCharFormat(format);
    textEdit->mergeCurrentCharFormat(format);
}

/*
	Update actions state. Triggered by style change event from QTextEdit.
*/
void MainWindowImpl::onFontChanged(const QFont &f)
{
    comboFont->setCurrentIndex(comboFont->findText(QFontInfo(f).family()));
    comboSize->setCurrentIndex(comboSize->findText(QString::number(f.pointSize())));
    actionBold->setChecked(f.bold());
    actionItalic->setChecked(f.italic());
    actionUnderline->setChecked(f.underline());
}

/*
	Update color action drawing. Triggered by style change event from QTextEdit.
*/
void MainWindowImpl::onColorChanged(const QColor &c)
{
    QPixmap pix(16, 16);
    pix.fill(c);
    action_Color->setIcon(pix);
}

/*
	Update alignment actions. Triggered by alignment change event from QTextEdit.
*/
void MainWindowImpl::onAlignmentChanged(Qt::Alignment a)
{
    if (a & Qt::AlignLeft)
    {
        actionAlignLeft->setChecked(true);
    }
    else if (a & Qt::AlignHCenter)
    {
        actionAlignCenter->setChecked(true);
    }
    else if (a & Qt::AlignRight)
    {
        actionAlignRight->setChecked(true);
    }
    else if (a & Qt::AlignJustify)
    {
        actionAlignJustify->setChecked(true);
    }
}

/*
	Settings methods.
*/
void MainWindowImpl::writeSettings()
{
#ifdef Q_WS_WIN
    QSettings settings(AppName() + ".ini", QSettings::IniFormat, 0);
#else
    QSettings settings(QSettings::IniFormat, QSettings::UserScope, AppName(), AppName(), 0);
#endif

    settings.beginGroup("MainWindow");
    settings.setValue("size", size());
    settings.setValue("pos", pos());
    settings.endGroup();
    
    settings.beginGroup("Docks");
    settings.setValue("MainDocks", this->saveState());
    settings.endGroup();
}

void MainWindowImpl::readSettings()
{
#ifdef Q_WS_WIN
    QSettings settings(AppName() + ".ini", QSettings::IniFormat, 0);
#else
    QSettings settings(QSettings::IniFormat, QSettings::UserScope, AppName(), AppName(), 0);
#endif

    settings.beginGroup("MainWindow");
    resize(settings.value("size", QSize(650, 500)).toSize());
    move(settings.value("pos", QPoint(200, 200)).toPoint());
    settings.endGroup();
    
    settings.beginGroup("Docks");
    this->restoreState(settings.value("MainDocks").toByteArray());
    settings.endGroup();
}

/*
	Events : slots programatically linked.
*/
void MainWindowImpl::onTrayIconActivated(QSystemTrayIcon::ActivationReason reason)
{
    if (reason == QSystemTrayIcon::Trigger)
        onActionSysShow();
}

void MainWindowImpl::onActionSysShow()
{
    if (!this->isVisible())
        this->show();

    this->setWindowState(this->windowState() & ~Qt::WindowMinimized | Qt::WindowActive);
}

void MainWindowImpl::onActionSysClose()
{
    m_closeFromMenu = true;
    this->close();
}

void MainWindowImpl::onActionMenuMoveUp()
{
    QTreeWidgetItem *current = treeWidget->currentItem();
    QTreeWidgetItem *parent = current->parent();
    if (parent)
    {
        int index1 = parent->indexOfChild(treeWidget->currentItem());
        int index2;
        if (index1 > 0)
        {
            index2 = index1 - 1;

            QTreeWidgetItem *item1 = parent->child(index1);
            bool expanded1 = item1->isExpanded();

            item1 = parent->takeChild(index1);
            parent->insertChild(index2, item1);

            item1->setExpanded(expanded1);
            treeWidget->setCurrentItem(item1);

            mainModel->setFileModified(true);
        }
    }
    else
    {
        int index1 = treeWidget->indexOfTopLevelItem(treeWidget->currentItem());
        int index2;
        if (index1 > 0)
        {
            index2 = index1 - 1;

            QTreeWidgetItem *item1 = treeWidget->topLevelItem(index1);

            bool expanded1 = item1->isExpanded();
            
            item1 = treeWidget->takeTopLevelItem(index1);
            treeWidget->insertTopLevelItem(index2, item1);
            
            item1->setExpanded(expanded1);
            treeWidget->setCurrentItem(item1);

            mainModel->setFileModified(true);
        }
    }
}

void MainWindowImpl::onActionMenuMoveDown()
{
    QTreeWidgetItem *current = treeWidget->currentItem();
    QTreeWidgetItem *parent = current->parent();
    if (parent)
    {
        int index1 = parent->indexOfChild(treeWidget->currentItem());
        int index2;
        if (index1 < (parent->childCount() - 1))
        {
            index2 = index1 + 1;

            QTreeWidgetItem *item1 = parent->child(index1);

            bool expanded1 = item1->isExpanded();

            item1 = parent->takeChild(index1);

            parent->insertChild(index2, item1);

            item1->setExpanded(expanded1);
            treeWidget->setCurrentItem(item1);

            mainModel->setFileModified(true);
        }
    }
    else
    {
        int index1 = treeWidget->indexOfTopLevelItem(treeWidget->currentItem());
        int index2;
        if (index1 < (treeWidget->topLevelItemCount() - 1))
        {
            index2 = index1 + 1;

            QTreeWidgetItem *item1 = treeWidget->topLevelItem(index1);

            bool expanded1 = item1->isExpanded();

            item1 = treeWidget->takeTopLevelItem(index1);
            treeWidget->insertTopLevelItem(index2, item1);

            item1->setExpanded(expanded1);
            treeWidget->setCurrentItem(item1);

            mainModel->setFileModified(true);
        }
    }
}

void MainWindowImpl::onActionMenuMoveRight()
{
    QTreeWidgetItem *current = treeWidget->currentItem();
    QTreeWidgetItem *parent = current->parent();

    if (parent)
    {
        int index = parent->indexOfChild(treeWidget->currentItem());
        if (index > 0)
        {
            int parentIndex = index - 1;
            QTreeWidgetItem *newParent;

            newParent = parent->child(parentIndex);
            int dataIndex = newParent->data(0, Qt::UserRole).toUInt();
            QString type = mainModel->getType(dataIndex);

            if ((type == "CATEGORY") &&
                    (newParent != current))
            {
                QTreeWidgetItem *child = parent->takeChild(index);
                newParent->addChild(child);
                treeWidget->setCurrentItem(child);

                mainModel->setFileModified(true);
            }
        }
    }
    else
    {
        int index = treeWidget->indexOfTopLevelItem(treeWidget->currentItem());

        if (index > 0)
        {
            int parentIndex = index - 1;
            QTreeWidgetItem *newParent;

            newParent = treeWidget->topLevelItem(parentIndex);
            int dataIndex = newParent->data(0, Qt::UserRole).toUInt();
            QString type = mainModel->getType(dataIndex);

            if ((type == "CATEGORY") &&
                    (newParent != current))
            {
                QTreeWidgetItem *child = treeWidget->takeTopLevelItem(index);
                newParent->addChild(child);
                treeWidget->setCurrentItem(child);

                mainModel->setFileModified(true);
            }
        }
    }
}

void MainWindowImpl::onActionMenuMoveLeft()
{
    QTreeWidgetItem *current = treeWidget->currentItem();
    QTreeWidgetItem *parent = current->parent();
    int index;

    if (parent)
    {
        index = parent->indexOfChild(treeWidget->currentItem());
        QTreeWidgetItem *newParent = parent->parent();
        QTreeWidgetItem *moved = parent->takeChild(index);
        if (newParent)
            newParent->addChild(moved);
        else
            treeWidget->addTopLevelItem(moved);
        treeWidget->setCurrentItem(moved);

        mainModel->setFileModified(true);
    }
}

void MainWindowImpl::onActionAddRootCategory()
{
    QTreeWidgetItem *childItem;

    bool ok;
    QString newName = QInputDialog::getText(this, tr("New root category"),
                                            tr("New root category name :"), QLineEdit::Normal, tr("NewCategory"), &ok);

    if (ok)
    {
        int index = mainModel->addItem(newName, "CATEGORY", "");

        childItem = new QTreeWidgetItem(treeWidget);

        // Setup icons and model.
        childItem->setIcon(0, mainModel->m_folderIcon);
        childItem->setText(0, newName);
        childItem->setData(0, Qt::UserRole, index);
    }
}

void MainWindowImpl::onActionAddRootPage()
{
    QTreeWidgetItem *childItem;

    bool ok;
    QString newName = QInputDialog::getText(this, tr("New root page"),
                                            tr("New root page name :"), QLineEdit::Normal, tr("NewPage"), &ok);

    if (ok)
    {
        int index = mainModel->addItem(newName, "PAGE", "");

        childItem = new QTreeWidgetItem(treeWidget);

        // Setup icons and model.
        childItem->setIcon(0, mainModel->m_bookmarkIcon);
        childItem->setText(0, newName);
        childItem->setData(0, Qt::UserRole, index);
    }
}

void MainWindowImpl::onActionMenuAddCategory()
{
    QTreeWidgetItem *childItem;
    QTreeWidgetItem *item = treeWidget->currentItem();

    bool ok;
    QString newName = QInputDialog::getText(this, tr("New category"),
                                            tr("New category name :"), QLineEdit::Normal, tr("NewCategory"), &ok);

    if (ok)
    {
        int index = mainModel->addItem(newName, "CATEGORY", "");

        if (item != NULL)
        {
            childItem = new QTreeWidgetItem(item);
            childItem->setFlags(item->flags());
        }
        else
            childItem = new QTreeWidgetItem(treeWidget);


        // Setup icons and model.
        childItem->setIcon(0, mainModel->m_folderIcon);
        childItem->setText(0, newName);
        childItem->setData(0, Qt::UserRole, index);
    }
}

void MainWindowImpl::onActionMenuAddPage()
{
    QTreeWidgetItem *childItem;
    QTreeWidgetItem *item = treeWidget->currentItem();

    bool ok;
    QString newName = QInputDialog::getText(this, tr("New page"),
                                            tr("New page name :"), QLineEdit::Normal, tr("NewPage"), &ok);

    if (ok)
    {
        int index = mainModel->addItem(newName, "PAGE", "");

        if (item != NULL)
        {
            childItem = new QTreeWidgetItem(item);
            childItem->setFlags(item->flags());
        }
        else
            childItem = new QTreeWidgetItem(treeWidget);


        // Setup icons and model.
        childItem->setIcon(0, mainModel->m_bookmarkIcon);
        childItem->setText(0, newName);
        childItem->setData(0, Qt::UserRole, index);
    }
}

void MainWindowImpl::onActionMenuRename()
{
    QTreeWidgetItem *item = treeWidget->currentItem();
    if (item != NULL)
    {
        int index = item->data(0, Qt::UserRole).toUInt();
        QString name = mainModel->getName(index);

        bool ok;
        QString newName = QInputDialog::getText(this, tr("Rename"),
                                                tr("New name :"), QLineEdit::Normal,
                                                name, &ok);
        if (ok)
        {
            mainModel->changeName(index, newName);
            item->setText(0, newName);
        }
    }
}

void MainWindowImpl::onActionMenuDelete()
{
    QTreeWidgetItem *item = treeWidget->currentItem();
    if (item != NULL)
    {
        int index = item->data(0, Qt::UserRole).toUInt();
        QString name = mainModel->getName(index);

        QMessageBox::StandardButton ret = QMessageBox::question(this, tr("Delete"), tr("Do you want to delete this item ?"),
                                          QMessageBox::Ok | QMessageBox::Cancel, QMessageBox::Cancel);

        if (ret == QMessageBox::Ok)
        {
            // If the deleted item is in the editor, clear it.
            if (item == mainModel->getCurrentItem())
            {
                textEdit->clear();
                textEdit->setEnabled(false);
            }

            // Delete the item, but NOT its data in the model, as it will create an offset
            // with index which will mess up the whole thing ;)
            delete item;
            mainModel->setFileModified(true);
        }
    }
}

/*
	When selecting a new item, update enabled state of "move" actions.
	A bit messy, but it work.
*/
void MainWindowImpl::onCurrentItemChanged(QTreeWidgetItem *current, QTreeWidgetItem *previous)
{
    if (mainModel != NULL)
    {
        QTreeWidgetItem *item = current;
        if (item != NULL)
        {
            int index = item->data(0, Qt::UserRole).toUInt();
            QString type = mainModel->getType(index);

            if (type == "PAGE")
            {
                actionMenuAddPage->setEnabled(false);
                actionMenuAddCategory->setEnabled(false);
                actionMenuRename->setEnabled(true);
                actionMenuDelete->setEnabled(true);
            }
            else if (type == "CATEGORY")
            {
                actionMenuAddPage->setEnabled(true);
                actionMenuAddCategory->setEnabled(true);
                actionMenuRename->setEnabled(true);
                actionMenuDelete->setEnabled(true);
            }

            QTreeWidgetItem *parent = item->parent();
            QTreeWidgetItem *upParent;
            int index1;
            int index2;
            int count1;

            if (parent)
            {
                actionMenuMoveLeft->setEnabled(true);
                index1 = parent->indexOfChild(item);
                count1 = parent->childCount();
                if (index1 > 0)
                {
                    upParent = parent->child(index1 - 1);
                    index2 = parent->indexOfChild(upParent);

                    int dataIndex = upParent->data(0, Qt::UserRole).toUInt();
                    QString type = mainModel->getType(dataIndex);
                    if (type == "CATEGORY")
                        actionMenuMoveRight->setEnabled(true);
                    else
                        actionMenuMoveRight->setEnabled(false);
                }
                else
                    actionMenuMoveRight->setEnabled(false);
            }
            else
            {
                actionMenuMoveLeft->setEnabled(false);
                index1 = treeWidget->indexOfTopLevelItem(item);
                count1 = treeWidget->topLevelItemCount();
                if (index1 > 0)
                {
                    upParent = treeWidget->topLevelItem(index1 - 1);
                    index2 = treeWidget->indexOfTopLevelItem(upParent);

                    int dataIndex = upParent->data(0, Qt::UserRole).toUInt();
                    QString type = mainModel->getType(dataIndex);
                    if (type == "CATEGORY")
                        actionMenuMoveRight->setEnabled(true);
                    else
                        actionMenuMoveRight->setEnabled(false);
                }
                else
                    actionMenuMoveRight->setEnabled(false);
            }

            if (index1 == 0)
                actionMenuMoveUp->setEnabled(false);
            else
                actionMenuMoveUp->setEnabled(true);

            if (index1 == (count1 - 1))
                actionMenuMoveDown->setEnabled(false);
            else
                actionMenuMoveDown->setEnabled(true);
        }
        else
        {
            actionAddRootCategory->setEnabled(true);
            actionAddRootPage->setEnabled(true);

            actionMenuAddPage->setEnabled(false);
            actionMenuAddCategory->setEnabled(false);
            actionMenuRename->setEnabled(false);
            actionMenuDelete->setEnabled(false);
            actionMenuMoveUp->setEnabled(false);
            actionMenuMoveDown->setEnabled(false);
            actionMenuMoveLeft->setEnabled(false);
            actionMenuMoveRight->setEnabled(false);
        }
    }
    else
    {
        actionAddRootCategory->setEnabled(false);
        actionAddRootPage->setEnabled(false);

        actionMenuAddPage->setEnabled(false);
        actionMenuAddCategory->setEnabled(false);
        actionMenuRename->setEnabled(false);
        actionMenuDelete->setEnabled(false);
        actionMenuMoveUp->setEnabled(false);
        actionMenuMoveDown->setEnabled(false);
        actionMenuMoveLeft->setEnabled(false);
        actionMenuMoveRight->setEnabled(false);
    }
}

/*
	Display the popup menu on the treeview.
*/
void MainWindowImpl::onTreeContextMenuRequested(QPoint pos)
{
    if (mainModel != NULL)
    {
        contextMenu->exec(QCursor::pos());
    }
}

/*
Double click on TreeWidget : update the editor if necessary.
*/
void MainWindowImpl::onTreeClick(QTreeWidgetItem *treeItem, int col)
{
    if ((treeItem != NULL) &&
            (mainModel != NULL))
    {
        mainModel->updateDisplay(treeItem);

        // Font
        QString font = m_confManager->defaultFont;
        int fontIndex = comboFont->findText(font);
        if (fontIndex != -1)
        {
            comboFont->setCurrentIndex(fontIndex);
            onTextFamily(font);
        }
        // Font size
        QString fontSize = m_confManager->defaultFontSize;
        int fontSizeIndex = comboSize->findText(fontSize);
        if (fontSizeIndex != -1)
        {
            comboSize->setCurrentIndex(fontSizeIndex);
            onTextSize(fontSize);
        }
        // Font color
        QTextCharFormat fmt;
        fmt.setForeground(m_confManager->defaultFontColor);
        mergeFormatOnWordOrSelection(fmt);
        onColorChanged(m_confManager->defaultFontColor);
    }
}

/*
	Close the application.
*/
void MainWindowImpl::doClose()
{
    if (mainModel != NULL)
        m_confManager->lastFile = mainModel->getFileName();
    else
        m_confManager->lastFile = "";

    m_trayIcon->hide();
    writeSettings();
    delete mainModel;
    delete m_confManager;	// Will save configuration.
    delete m_styleManager;	// Will save styles.
}

/*
	Hide the application to tray.
*/
void MainWindowImpl::doCloseToTray()
{
    this->hide();
    if (m_confManager->showMessageOnCloseToTray)
        m_trayIcon->showMessage(AppDisplayName(),
                                AppDisplayName() + tr(" has been minimized to tray.\nYou can show it by clicking on its icon."),
                                QSystemTrayIcon::MessageIcon(QSystemTrayIcon::Information), 5000);
}

/*
	Close request.
*/
void MainWindowImpl::closeEvent(QCloseEvent *event)
{
	// m_closeFromMenu equals true when user has clicked on any of the quit menu,
	// but equals false when closing using top right window button.
    if ((m_closeFromMenu) ||
            (!m_confManager->useTrayIcon) ||
            ((m_confManager->useTrayIcon) &&
             (!m_confManager->closeToTray)))
    {
        m_closeFromMenu = false;
        if (mainModel != NULL)
        {
            if (mainModel->askForSaveAndSave(this))
            {
                event->accept();
                doClose();
            }
            else
                event->ignore();
        }
        else
        {
            event->accept();
            doClose();
        }
    }
    else
    {
        event->ignore();
        doCloseToTray();
    }
}

/*
Alignement actions triggered : change alignment.
*/
void MainWindowImpl::onTextAlign(QAction *a)
{
    if (a == actionAlignLeft)
        textEdit->setAlignment(Qt::AlignLeft);
    else if (a == actionAlignCenter)
        textEdit->setAlignment(Qt::AlignHCenter);
    else if (a == actionAlignRight)
        textEdit->setAlignment(Qt::AlignRight);
    else if (a == actionAlignJustify)
        textEdit->setAlignment(Qt::AlignJustify);
}

/*
Font combo change.
*/
void MainWindowImpl::onTextFamily(const QString &f)
{
    QTextCharFormat fmt;
    fmt.setFontFamily(f);
    mergeFormatOnWordOrSelection(fmt);
    textEdit->setFontFamily(f);
    textEdit->setFocus();
}

/*
Font size change.
*/
void MainWindowImpl::onTextSize(const QString &p)
{
    QTextCharFormat fmt;
    fmt.setFontPointSize(p.toFloat());
    mergeFormatOnWordOrSelection(fmt);
    textEdit->setFontPointSize(p.toFloat());
    textEdit->setFocus();
}

/*
Events : Automaticaly generated by QDevelop
*/
void MainWindowImpl::onClipboardDataChanged()
{
    actionPaste->setEnabled(!QApplication::clipboard()->text().isEmpty());
}

void MainWindowImpl::on_action_Quit_triggered()
{
    m_closeFromMenu = true;
    this->close();
}

void MainWindowImpl::openFile(QString fileName)
{
    // Delete old model.
    if (mainModel != NULL)
        delete mainModel;

    // Create new model and open the file.
    mainModel = new Model(treeWidget, textEdit, fileName);
    if (mainModel->open())
    {
    	actionAddRootCategory->setEnabled(true);
	    actionAddRootPage->setEnabled(true);

	    statusBar()->showMessage(tr("File opened : ") + mainModel->getFileName());
   	}
	else
	{
		delete mainModel;
		mainModel = NULL;
		statusBar()->showMessage(tr("Unabled to find file : ") + fileName);
	}    
}

/*
Open a file.
*/
void MainWindowImpl::on_action_Open_triggered()
{
    bool ret;

    // If a file is already opened, check if the user cant to save it, if its not.
    if (mainModel != NULL)
        ret = mainModel->askForSaveAndSave(this);
    else
        ret = true;

    if (ret)
    {
        // Ask for filename.
        QString fileName = QFileDialog::getOpenFileName(this, tr("Open a file"),
                           QDir::currentPath(),
                           tr("XML Files (*.xml)"));
        if (fileName.isEmpty())
            return;

        openFile(fileName);
    }
}

/*
Create a new file.
*/
void MainWindowImpl::on_action_New_triggered()
{
    bool ret;

    // If a file is already opened, check if the user cant to save it, if its not.
    if (mainModel != NULL)
        ret = mainModel->askForSaveAndSave(this);
    else
        ret = true;

    if (ret)
    {
        // Ask for filename.
        QString fileName = QFileDialog::getSaveFileName(this, tr("New file"),
                           QDir::currentPath(),
                           tr("XML Files (*.xml)"));
        if (fileName.isEmpty())
            return;

        // Delete old model.
        if (mainModel != NULL)
            delete mainModel;

        // Create a new one.
        mainModel = new Model(treeWidget, textEdit, fileName);

        actionAddRootCategory->setEnabled(true);
        actionAddRootPage->setEnabled(true);

        statusBar()->showMessage(tr("New file : ") + mainModel->getFileName());
    }
}

/*
Save current file.
*/
void MainWindowImpl::on_action_Save_triggered()
{
    if (mainModel != NULL)
    {
        mainModel->save();
        statusBar()->showMessage(tr("File saved : ") + mainModel->getFileName());
    }
}

/*
Save current file under a new name.
*/
void MainWindowImpl::on_actionSave_as_triggered()
{
    if (mainModel != NULL)
    {
        // Ask for name.
        QString fileName = QFileDialog::getSaveFileName(this, tr("Save a file"),
                           QDir::currentPath(),
                           tr("XML Files (*.xml)"));
        if (fileName.isEmpty())
            return;

        mainModel->saveAs(fileName);

        statusBar()->showMessage(tr("File saved as : ") + mainModel->getFileName());
    }
}

/*
	Editor actions.
*/
void MainWindowImpl::on_actionBold_triggered()
{
    QTextCharFormat fmt;
    fmt.setFontWeight(actionBold->isChecked() ? QFont::Bold : QFont::Normal);
    mergeFormatOnWordOrSelection(fmt);
}

void MainWindowImpl::on_actionItalic_triggered()
{
    QTextCharFormat fmt;
    fmt.setFontItalic(actionItalic->isChecked());
    mergeFormatOnWordOrSelection(fmt);
}

void MainWindowImpl::on_actionUnderline_triggered()
{
    QTextCharFormat fmt;
    fmt.setFontUnderline(actionUnderline->isChecked());
    mergeFormatOnWordOrSelection(fmt);
}

void MainWindowImpl::on_textEdit_currentCharFormatChanged(QTextCharFormat format)
{
    onFontChanged(format.font());
    onColorChanged(format.foreground().color());
}

void MainWindowImpl::on_action_Color_triggered()
{
    QColor col = QColorDialog::getColor(textEdit->textColor(), this);
    if (!col.isValid())
        return;

    QTextCharFormat fmt;
    fmt.setForeground(col);
    mergeFormatOnWordOrSelection(fmt);
    onColorChanged(col);
}

void MainWindowImpl::on_textEdit_cursorPositionChanged()
{
    onAlignmentChanged(textEdit->alignment());
}

/*
	Misc. actions.
*/
void MainWindowImpl::on_actionAbout_Qt_triggered()
{
    QMessageBox::aboutQt(this, AppDisplayName());
}

void MainWindowImpl::on_action_About_triggered()
{
    AboutDialogImpl *aboutDlg = new AboutDialogImpl(this, Qt::WindowTitleHint | Qt::WindowSystemMenuHint);
    aboutDlg->setData(AppDisplayName(),
                      AppVersion());
    aboutDlg->exec();
    delete aboutDlg;    
    //QMessageBox::about(this, AppDisplayName(), tr("<html><head></head><body><p><span style=\" font-size:12pt; font-weight:600;\">About ") + AppDisplayName() + "</span></p><p></p><p>" + AppDisplayName() + tr(" is a note-taking application. Each note can be classified in categories.</p><p>It is released under the terms of GPL v2 (See LICENSE file).</p><p>") + AppDisplayName() + tr(" is made with <a href=\"http://trolltech.com/products/qt\">Qt</a> under <a href=\"http://qdevelop.org/\">QDevelop</a>.</p><p>Version ") + AppVersion() + "</p></body></html>");
}

void MainWindowImpl::on_actionPrint_triggered()
{
    if ((mainModel != NULL) &&
            (mainModel->getCurrentItem() != NULL))
    {
        QTextDocument *document = textEdit->document();
        QPrinter printer;

        QPrintDialog *dialog = new QPrintDialog(&printer, this);
        dialog->setWindowTitle(tr("Print Document"));
        if (dialog->exec() != QDialog::Accepted)
            return;

        document->print(&printer);
    }
}

void MainWindowImpl::on_actionExport_PDF_triggered()
{
    if ((mainModel != NULL) &&
            (mainModel->getCurrentItem() != NULL))
    {
        QString fileName = QFileDialog::getSaveFileName(this, tr("Export PDF"),
                           QString(), "*.pdf");
        if (!fileName.isEmpty())
        {
            if (QFileInfo(fileName).suffix().isEmpty())
                fileName.append(".pdf");
            QPrinter printer(QPrinter::HighResolution);
            printer.setOutputFormat(QPrinter::PdfFormat);
            printer.setOutputFileName(fileName);
            textEdit->document()->print(&printer);
        }
    }
}

void MainWindowImpl::on_actionPostScript_triggered()
{
    if ((mainModel != NULL) &&
            (mainModel->getCurrentItem() != NULL))
    {
        QString fileName = QFileDialog::getSaveFileName(this, tr("Export PostScript"),
                           QString(), "*.ps");
        if (!fileName.isEmpty())
        {
            if (QFileInfo(fileName).suffix().isEmpty())
                fileName.append(".ps");
            QPrinter printer(QPrinter::HighResolution);
            printer.setOutputFormat(QPrinter::PostScriptFormat);
            printer.setOutputFileName(fileName);
            textEdit->document()->print(&printer);
        }
    }
}

void MainWindowImpl::on_actionStyle_editor_triggered()
{
    StyleEditorImpl *styleEditor = new StyleEditorImpl(this, 0);
    styleEditor->setManagers(m_confManager, m_styleManager);
    styleEditor->exec();
    delete styleEditor;
    m_styleManager->updateComboStyle(comboStyle);
}

void MainWindowImpl::on_action_Apply_current_style_triggered()
{
    if ((comboStyle->count() > 0) &&
            (textEdit->isEnabled()))
    {
        int index = comboStyle->itemData(comboStyle->currentIndex(), Qt::UserRole).toUInt();
        // Font
        QString font = m_styleManager->getStyleFont(index);
        int fontIndex = comboFont->findText(font);
        if (fontIndex != -1)
        {
            comboFont->setCurrentIndex(fontIndex);
            onTextFamily(font);
        }
        // Font size
        QString fontSize = m_styleManager->getStyleSize(index);
        int fontSizeIndex = comboSize->findText(fontSize);
        if (fontSizeIndex != -1)
        {
            comboSize->setCurrentIndex(fontSizeIndex);
            onTextSize(fontSize);
        }
        // Font color
        QTextCharFormat fmt;
        fmt.setForeground(m_styleManager->getStyleColor(index));
        mergeFormatOnWordOrSelection(fmt);
        onColorChanged(m_styleManager->getStyleColor(index));
        // Bold, Italic, Underline
        actionBold->setChecked(m_styleManager->getStyleBold(index));
        on_actionBold_triggered();
        actionItalic->setChecked(m_styleManager->getStyleItalic(index));
        on_actionItalic_triggered();
        actionUnderline->setChecked(m_styleManager->getStyleUnderline(index));
        on_actionUnderline_triggered();
        // Alignment
        switch (m_styleManager->getStyleAlignment(index))
        {
        case 0 :
            actionAlignLeft->setChecked(true);
            onTextAlign(actionAlignLeft);
            break;
        case 1 :
            actionAlignCenter->setChecked(true);
            onTextAlign(actionAlignCenter);
            break;
        case 2 :
            actionAlignRight->setChecked(true);
            onTextAlign(actionAlignRight);
            break;
        case 3 :
            actionAlignJustify->setChecked(true);
            onTextAlign(actionAlignJustify);
            break;
        default :
            actionAlignLeft->setChecked(true);
            onTextAlign(actionAlignLeft);
            break;
        }
    }
}

void MainWindowImpl::on_action_Options_triggered()
{
    ConfigurationDlgImpl *confEditor = new ConfigurationDlgImpl(this, 0);
    confEditor->setConfigurationManager(m_confManager);
    int result = confEditor->exec();

    if (result == QDialog::Accepted)
        applyConfiguration();

    delete confEditor;
}

void MainWindowImpl::on_action_Search_triggered()
{
	QMessageBox::information(this, tr("Search"), tr("Coming soon..."));
}
